/*
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *
 *   版权所有  2014-2015 成都星锐蓝海网络科技有限公司
 *   商业许可请联系  +86-18682011860    QQ:66442834
 *   
 */


#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "xyz_log.h"

#define CLR_NONE          "\033[m"
#define CLR_RED           "\033[0;32;31m"
#define CLR_LIGHT_RED     "\033[1;31m"
#define CLR_GREEN         "\033[0;32;32m"
#define CLR_LIGHT_GREEN   "\033[1;32m"
#define CLR_BLUE          "\033[0;32;34m"
#define CLR_LIGHT_BLUE    "\033[1;34m"
#define CLR_GRAY          "\033[0;37m"
#define CLR_DARY_GRAY     "\033[1;30m"
#define CLR_CYAN          "\033[0;36m"
#define CLR_LIGHT_CYAN    "\033[1;36m"
#define CLR_PURPLE        "\033[0;35m"
#define CLR_LIGHT_PURPLE  "\033[1;35m"
#define CLR_BROWN         "\033[0;33m"
#define CLR_YELLOW        "\033[0;33m"
#define CLR_LIGHT_YELLOW  "\033[1;33m"
#define CLR_WHITE         "\033[1;37m"


static char *__xyz_log_colour_array[] = {
    CLR_WHITE,
    CLR_WHITE,
    CLR_WHITE,
    CLR_RED,
    CLR_YELLOW,
    CLR_GREEN,
    CLR_BLUE,
    CLR_GREEN
};

static char *__xyz_log_level_string[] = {
    "EMESG",
    "ALERT",
    "CRIT",
    "Error",
    "Warn",
    "Notice",
    "Info",
    "Debug"
};

volatile int __xyz_log_level = XYZ_LOG_LEVEL_EMESG;

static pthread_mutex_t S_xyz_log_wrlock = PTHREAD_MUTEX_INITIALIZER;

static char S_xyz_log_path[1024];

static FILE *S_xyz_log_file = NULL;

static int S_xyz_log_fd = 0;

static int S_xyz_log_out_std = 1;

static long int S_xyz_log_size_max = 0;

static long int S_xyz_log_curr_size = 0;

int xyz_log_init(const char *file, unsigned int level, unsigned long int size)
{
	long int flen = 0;
	if (!file) {
		S_xyz_log_file = stderr;
	} else {
		if (!strncmp(file, "stdout", 6)) {
			S_xyz_log_file = stdout;
		} else if (!strncmp(file, "stderr", 6)) {
			S_xyz_log_file = stderr;
		} else {
			FILE *f = fopen(file, "a");
			if (!f) {
				S_xyz_log_file = stderr;
				S_xyz_log_out_std = 1;
				return -1;
			}
			strncpy(S_xyz_log_path, file, 1023);
			S_xyz_log_out_std = 0;
			S_xyz_log_file = f;
			S_xyz_log_fd = fileno(f);
			flen = ftell(f);
			if (flen < 0) {
				S_xyz_log_file = stderr;
				S_xyz_log_out_std = 1;
				fclose(S_xyz_log_file);
				return -1;
			}
			S_xyz_log_curr_size = flen;
		}
	}
	__xyz_log_level = level > XYZ_LOG_LEVEL_DEBUG ? XYZ_LOG_LEVEL_DEBUG : level;
	if (size > 0) {
		S_xyz_log_size_max = size;
	}
	return 0;
}

void xyz_log_close(void)
{
	pthread_mutex_lock(&S_xyz_log_wrlock);
	if (0 == S_xyz_log_out_std) {
		fclose(S_xyz_log_file);
	}
	S_xyz_log_file = stderr;
	S_xyz_log_out_std = 1;
	__xyz_log_level = XYZ_LOG_LEVEL_EMESG;
	pthread_mutex_unlock(&S_xyz_log_wrlock);
}

void __xyz_log_base_print(int level, const char *format, ...)
{
	time_t t;
	long int rc = 0;
	time(&t);
	struct tm tm;
	localtime_r((const time_t*) &t, &tm);
	va_list vlist;
	if (S_xyz_log_file) {
		pthread_mutex_lock(&S_xyz_log_wrlock);
		rc = fprintf(S_xyz_log_file, "%04d-%02d-%02d %02d:%02d:%02d %s : ",
				tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
				tm.tm_hour, tm.tm_min, tm.tm_sec, __xyz_log_level_string[level]);
		va_start(vlist, format);
		rc += vfprintf(S_xyz_log_file, format, vlist);
		va_end(vlist);
		rc += fprintf(S_xyz_log_file, "\n");
		fflush(S_xyz_log_file);
		if ((0 == S_xyz_log_out_std) && (S_xyz_log_size_max > 0) && (rc > 0)) {
			if (S_xyz_log_curr_size >= (S_xyz_log_size_max - rc)) {
				fclose(S_xyz_log_file);
				S_xyz_log_file = fopen(S_xyz_log_path, "w");
				if (!S_xyz_log_file) {
					S_xyz_log_file = stderr;
					S_xyz_log_out_std = 1;
				}
				S_xyz_log_curr_size = 0;
			} else {
				S_xyz_log_curr_size += rc;
			}
		}
		pthread_mutex_unlock(&S_xyz_log_wrlock);
	}
}

void __xyz_log_base_colour_print(int level, const char *filename, int line, const char *function,const char *format, ...)
{
	long int rc = 0;
	time_t t;
	time(&t);
	struct tm tm;
	localtime_r((const time_t*) &t, &tm);
	va_list vlist;
	if (S_xyz_log_file) {
		pthread_mutex_lock(&S_xyz_log_wrlock);
		rc = fprintf(S_xyz_log_file, "%s[%04d-%02d-%02d %02d:%02d:%02d] %s %s:%d %s: ",
				__xyz_log_colour_array[level], tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
				tm.tm_hour, tm.tm_min, tm.tm_sec, __xyz_log_level_string[level],
				filename, line, function);
		va_start(vlist, format);
		rc += vfprintf(S_xyz_log_file, format, vlist);
		va_end(vlist);
		rc += fprintf(S_xyz_log_file, CLR_NONE"\n");
		fflush(S_xyz_log_file);
		if ((0 == S_xyz_log_out_std) && (S_xyz_log_size_max > 0) && (rc > 0)) {
			if (S_xyz_log_curr_size >= (S_xyz_log_size_max - rc)) {
				fclose(S_xyz_log_file);
				S_xyz_log_file = fopen(S_xyz_log_path, "w");
				if (!S_xyz_log_file) {
					S_xyz_log_file = stderr;
					S_xyz_log_out_std = 1;
				}
				S_xyz_log_curr_size = 0;
			} else {
				S_xyz_log_curr_size += rc;
			}
		}
		pthread_mutex_unlock(&S_xyz_log_wrlock);
	}
}
